package sip

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/fatih/structs"

	"gitee.com/larry_wan/go-lib/utils"
)

type Digest struct {
	Scheme    string
	Username  string
	Realm     string
	Nonce     string
	URI       string
	Response  string
	Algorithm string
	CNonce    string
	Qop       string
	NC        string
	Method    string
	Entity    string
}

func (d Digest) String() string {
	buf, _ := json.MarshalIndent(structs.Map(&d), "", " ")
	return string(buf)
}

func (d *Digest) HA1(password string) (ret string) {
	ha1 := utils.MD5(fmt.Sprintf("%s:%s:%s", d.Username, d.Realm, password))
	switch strings.ToLower(d.Algorithm) {
	case "md5-sess":
		ret = utils.MD5(fmt.Sprintf("%s:%s:%s", ha1, d.Nonce, d.CNonce))
	case "md5":
		fallthrough
	default:
		ret = ha1
	}
	return
}

func (d *Digest) Calculate(password string) (response string) {
	defer func() {
		utils.Logf("digest calculate response[%s]", response)
	}()
	switch strings.ToLower(d.Scheme) {
	case "digest":
		switch strings.ToLower(d.Qop) {
		case "auth-init", "auth-int":
			ha3 := utils.MD5(fmt.Sprintf("%s:%s:%s", d.Method, d.URI, utils.MD5(d.Entity)))
			response = utils.MD5(fmt.Sprintf("%s:%s:%s:%s:%s:%s", d.HA1(password), d.Nonce, d.NC, d.CNonce, d.Qop, ha3))
		case "auth":
			ha3 := utils.MD5(fmt.Sprintf("%s:%s", d.Method, d.URI))
			response = utils.MD5(fmt.Sprintf("%s:%s:%s:%s:%s:%s", d.HA1(password), d.Nonce, d.NC, d.CNonce, d.Qop, ha3))
			return
		default:
			ha3 := utils.MD5(fmt.Sprintf("%s:%s", d.Method, d.URI))
			response = utils.MD5(fmt.Sprintf("%s:%s:%s", d.HA1(password), d.Nonce, ha3))
		}
	case "basic":
		fallthrough
	default:
		response = base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", d.Username, password)))
	}
	return
}
